import { _decorator, postProcess, EffectAsset, Material, Color, renderer, rendering, gfx } from "cc";
const { ccclass, property, menu, executeInEditMode } = _decorator;
const { PostProcessSetting, SettingPass, BlitScreenPass } = postProcess

@ccclass('OutlineSettings')
@menu('PostProcess/OutinePP')
@executeInEditMode
export class OutlineSettings extends PostProcessSetting {
    @property(EffectAsset)
    _effectAsset: EffectAsset | undefined

    @property(EffectAsset)
    get effect () {
        return this._effectAsset;
    }
    set effect (v) {
        this._effectAsset = v;
        if (this._effectAsset == null) {
            this._material = null;
        } else {
            if (this._material == null) {
                this._material = new Material();
            }
            // this._material.reset({effectAsset : this._effectAsset});
            this.initMaterial();
            this.updateMaterial();
        }
    }

    @property
    outlineSize = 1.0

    @property(Color)
    outlineColor : Color = new Color(Color.WHITE);

    private _pass : renderer.Pass;
    private _outlineSizeHandle = 0;
    private _outlineColorHandle = 0;

    private _material : Material;
    public get material() : Material {
        return this._material;
    }

    initMaterial() {
        if (!this._material) {
            return;
        }

        this._pass = this._material.passes[0];
        this._outlineColorHandle = this._pass.getHandle("_OutlineCol");
        this._outlineSizeHandle = this._pass.getHandle("_OutlineSize");
    }

    updateMaterial()
    {
        if (!this._material) {
            return;
        }
        this._pass.setUniform(this._outlineColorHandle, this.outlineColor);
        this._pass.setUniform(this._outlineSizeHandle, this.outlineSize);
    }

    protected start(): void {
        if (this._effectAsset) {
            this._material = new Material();
            this._material.initialize({effectAsset: this._effectAsset});
            this.initMaterial();
            this.updateMaterial();
        }
    }
}

export class OutlinePass extends SettingPass {
    name = 'OutlinePass';
    outputNames: string[] = ['OutlinePassMap'];

    get setting () { return this.getSetting(OutlineSettings); }

    checkEnable(camera: renderer.scene.Camera): boolean {
        let enable = super.checkEnable(camera);
        if (postProcess.disablePostProcessForDebugView()) {
            enable = false;
        }
        return enable && this.setting.material != null;
    }

    render(camera: renderer.scene.Camera, ppl: rendering.Pipeline) {
        const setting = this.setting;
        if (!setting.material) {
            return;
        }

        let passContext = this.context;
        passContext.material = setting.material;

        const cameraID = this.getCameraUniqueID(camera);
        const cameraName = `Camera${cameraID}`;
        const passViewport = passContext.passViewport;

        passContext.clearBlack();
        const format = gfx.Format.RGBA8;

        let input = this.lastPass!.slotName(camera, 0);
        let output = this.slotName(camera);
        setting.updateMaterial();

        passContext
            .updatePassViewPort()
            .addRenderPass('outline-pass', `outline-pass${cameraID}`)
            .setPassInput(input, '_OutlinePPRt')
            .addRasterView(output, format)
            .blitScreen(0)
            .version();
        
    }
}

let builder = rendering.getCustomPipeline('Custom') as postProcess.PostProcessBuilder;
if (builder) {
    builder.insertPass(new OutlinePass, BlitScreenPass);
}


